home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
SGI Developer Toolbox 6.1
/
SGI Developer Toolbox 6.1 - Disc 4.iso
/
public
/
plan
/
src
/
main.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-08-01
|
25KB
|
876 lines
/*
* Initializes everything and starts a calendar window for the current
* month. The interval timer (for autosave and entry recycling) and a
* few routines used by everyone are also here.
*
* main(argc, argv) Guess.
* fatal(char *fmt, ...) Prints an error message and exits.
* print_button(w, fmt, ...) Prints a string into a string Label
* or PushButton.
* print_text_button(w, fmt, ...) Prints a string into a Text button.
* print_pixmap(w, n) Prints a pixmap into a Pixmap label.
* set_color(col) Sets the foreground color to one of
* the predefined colors (COL_*).
* resynchronize_daemon() Called when the database on disk has
* changed; tell the daemon to re-read.
*
* Author: thomas@bitrot.in-berlin.de (Thomas Driemeyer)
*/
#include <stdio.h>
#include <time.h>
#include <fcntl.h>
#ifndef VARARGS
#include <stdarg.h>
#endif
#ifndef MIPS
#include <unistd.h>
#include <stdlib.h>
#endif
#include <ctype.h>
#include <signal.h>
#include <string.h>
#include <sys/types.h>
#include <Xm/Xm.h>
#include <X11/StringDefs.h>
#ifdef JAPAN
#include <jctype.h>
#include <locale.h>
#endif
#include "cal.h"
#include "version.h"
#ifdef JAPAN
#ifndef LOCALE_SJIS
#define LOCALE_SJIS "ja_JP.SJIS"
#endif
#ifndef LOCALE_EUC
#define LOCALE_EUC "ja_JP.EUC"
#endif
#endif
extern char *mkdatestring(), *mktimestring(), *mknotestring();
extern char *mystrdup(), *parse_holidays();
extern time_t tm_to_time(), parse_datestring();
extern struct tm *time_to_tm();
extern time_t get_time();
extern void set_tzone();
extern BOOL startup_lock(), lookup_entry(), lookup_next_entry();
static void init_resources(), init_colors(), init_fonts(), init_daemon();
static void timer_callback(), usage(), non_interactive(), sighand();
static int dumptoday();
#ifdef MIPS
void exit();
extern char *getenv();
#endif
Display *display; /* everybody uses the same server */
GC jgc, gc; /* graphic context, Japanese and std */
XtAppContext app; /* application handle */
Widget toplevel; /* top-level shell for icon name */
struct mainmenu mainmenu; /* all important main window widgets */
struct config config; /* global configuration data */
char *progname; /* argv[0] */
BOOL interactive; /* interactive or fast appt entry? */
XFontStruct *font[NFONTS]; /* fonts: FONT_* */
Pixel color[NCOLS]; /* colors: COL_* */
int curr_month; /* month being displayed, 0..11 */
int curr_year; /* year being displayed, since 1900 */
struct list *mainlist; /* list of all schedule entries */
extern Pixmap pixmap[NPICS]; /* common symbols */
static BOOL nodaemon; /* don't insist on a daemon (-s) */
static XtIntervalId timer_id; /* identifies 60-second timer */
static BOOL reread; /* need to re-read database file */
extern char lockpath[]; /* lockfile path (from lock.c) */
#ifdef JAPAN
char *localename; /* locale name */
unsigned short (*kanji2jis)() = euc2jis; /* or sjis2jis() */
#endif
static String fallbacks[] = {
#include "resources.h"
#include "print_res.h"
NULL
};
/*
* initialize everything and create the main calendar window
*/
main(argc, argv)
int argc;
char *argv[];
{
int n, i;
time_t now;
struct tm *tm;
char buf[80], *name;
BOOL nofork = FALSE;
BOOL nolock = FALSE;
char *errmsg;
interactive = FALSE;
if ((progname = strrchr(argv[0], '/')) && progname[1])
progname++;
else
progname = argv[0];
tzset();
now = get_time();
tm = time_to_tm(now);
curr_month = tm->tm_mon;
curr_year = tm->tm_year;
set_tzone();
#ifdef JAPAN
if (strcmp(localename = setlocale(LC_CTYPE, ""), JAPAN_SJIS)) {
if(strcmp(localename, JAPAN_EUC))
fprintf(stderr,
"Unknown locale name %s, defaulting to EUC\n",
localename);
} else
kanji2jis = sjis2jis;
#endif
if (argc > 1 && isdigit(*argv[1])) { /* non-interactive? */
non_interactive(argc, argv);
_exit(0);
}
for (n=1; n < argc; n++) /* options */
if (*argv[n] != '-')
usage();
else if (argv[n][2] < 'a' || argv[n][2] > 'z')
switch(argv[n][1]) {
case 'd':
for (i=0; fallbacks[i]; i++)
printf("%s%s\n", progname,
fallbacks[i]);
fflush(stdout);
return(0);
case 'v':
fprintf(stderr, "%s: %s %s\n",
progname, VERSION, PATCHLEVEL);
return(0);
case 's':
nodaemon = TRUE;
break;
case 'f':
nofork = TRUE;
break;
case 'k':
nolock = TRUE;
break;
case 't':
return(dumptoday(argv[n][2] ?
argv[n]+2 : argv[n+1]));
default:
usage();
}
else
break;
(void)umask(0077);
if (!nofork) { /* background */
PID_T pid = fork();
if (pid < 0)
perror("can't fork");
else if (pid > 0)
_exit(0);
}
interactive = TRUE; /* init interactive */
config.ewarn_window = TRUE;
config.lwarn_window = TRUE;
config.alarm_window = TRUE;
config.early_time = 45*60;
config.late_time = 5*60;
name = getenv("LOGNAME");
if (!name) name = getenv("USER");
if (!name) name = getenv("user");
if (!name) name = "username";
sprintf(buf, "Mail -s %%s %.65s", name);
config.mailer = mystrdup(buf);
toplevel = XtAppInitialize(&app, "Plan", NULL, 0,
# ifndef XlibSpecificationRelease
(Cardinal *)&argc, argv,
# else
&argc, argv,
# endif
fallbacks, NULL, 0);
# ifdef EDITRES
XtAddEventHandler(toplevel, (EventMask)0, TRUE,
_XEditResCheckMessages, NULL);
# endif
display = XtDisplay(toplevel);
jgc = XCreateGC(display, DefaultRootWindow(display), 0, 0);
gc = XCreateGC(display, DefaultRootWindow(display), 0, 0);
init_resources();
init_colors();
init_fonts();
init_pixmaps();
set_icon(toplevel, 0);
create_list(&mainlist);
(void)readfile(&mainlist, DB_PUB_PATH, TRUE);
(void)readfile(&mainlist, DB_PRIV_PATH, FALSE);
create_cal_widgets(toplevel);
if (config.autodel)
(void)recycle_all(mainlist, TRUE, 0);
signal(SIGHUP, sighand);
/* lockfile ok? */
if (!startup_lock(PLAN_PATH, nolock))
create_multiple_popup(nolock);
/* holidays ok? */
if (errmsg = parse_holidays(curr_year, TRUE))
create_error_popup(mainmenu.cal, 0, errmsg);
/* start */
timer_id = XtAppAddTimeOut(app, TIMER_PERIOD, timer_callback, 0);
XtRealizeWidget(toplevel);
resynchronize_daemon();
XtAppMainLoop(app);
return(0);
}
/*
* if the first argument is numeric, we are in non-interactive mode. Add a
* single appointment at the specified time, signal the plan program to
* re-read the database, and terminate.
*/
static void non_interactive(argc, argv)
int argc; /* arguments from main */
char *argv[]; /* arguments from main */
{
time_t now;
struct tm *tm; /* current date and time */
struct tm tm1; /* for time conversion */
time_t trigger; /* trigger date and time */
char msg[1024]; /* note from command line */
struct entry entry; /* appointment to add */
int n, i; /* char and arg counters */
char lockfile[80]; /* plan lockfile, for sighup */
FILE *fp; /* for reading lockfile */
PID_T pid = 0; /* interactive plan PID */
n = strlen(argv[1]);
if (n != 4 && n != 8)
usage();
i = atoi(argv[1]);
now = get_time();
tm = time_to_tm(now);
tm1.tm_sec = 0;
tm1.tm_min = i % 100;
tm1.tm_hour = (i/100) % 100;
tm1.tm_mday = n == 8 ? (i/10000)%100 : tm->tm_mday;
tm1.tm_mon = n == 8 ? (i/1000000)%100-1 : tm->tm_mon;
tm1.tm_year = curr_year + (tm1.tm_mon < tm->tm_mon);
trigger = tm_to_time(&tm1);
for (i=2; i < argc; i++) {
if (strlen(msg) + strlen(argv[i]) > 1021)
break;
strcat(msg, argv[i]);
if (i < argc-1)
strcat(msg, " ");
}
entry.message = 0;
entry.script = 0;
entry.meeting = 0;
entry.note = msg;
entry.time = trigger;
entry.length = 0;
entry.early_warn = 0;
entry.late_warn = 0;
entry.rep_every = 0;
entry.rep_last = 0;
entry.rep_weekdays = 0;
entry.rep_days = 0;
entry.rep_yearly = 0;
entry.suspended = 0;
entry.private = 0;
entry.noalarm = 0;
entry.notime = 0;
entry.triggered = 0;
create_list(&mainlist);
(void)readfile(&mainlist, DB_PUB_PATH, TRUE);
(void)readfile(&mainlist, DB_PRIV_PATH, FALSE);
(void)add_entry(&mainlist, &entry);
write_database(mainlist, DB_PUB_PATH, WR_PUBLIC | WR_CONFIG);
write_database(mainlist, DB_PRIV_PATH, WR_PRIVATE);
resynchronize_daemon();
printf("%s %s \"%.57s\"\n", mkdatestring(trigger),
mktimestring(trigger, FALSE), msg);
sprintf(lockfile, PLAN_PATH, (int)getuid());
if (fp = fopen(lockfile, "r")) {
fscanf(fp, "%d", &pid);
if (pid > 1)
(void)kill(pid, SIGHUP);
}
}
/*
* -t option, prints an ascii summary of all appointments on a day. This
* is useful for cronjobs that send mail every morning. Return 1 if there
* are no entries; this will be used as exit code (to suppress mail).
*/
static int dumptoday(date)
char *date; /* dump what day, "" is today */
{
struct lookup lookup; /* for finding entries */
time_t start; /* 0:00 of the day to dump */
BOOL found; /* TRUE if there is another entry */
int numfound = 0; /* # of entries dumped */
char timestr[20]; /* buffer for time string */
create_list(&mainlist);
(void)readfile(&mainlist, DB_PUB_PATH, TRUE);
(void)readfile(&mainlist, DB_PRIV_PATH, FALSE);
rebuild_repeat_chain(mainlist);
start = parse_datestring(date && *date ? date : "today", 0);
found = lookup_entry(&lookup, mainlist, start, FALSE, FALSE);
while (found && lookup.trigger < start + 86400) {
struct entry *ep = &mainlist->entry[lookup.index];
if (!ep->suspended) {
if (!numfound++)
printf("%s:\n", mkdatestring(start));
strcpy(timestr, mktimestring(lookup.trigger, FALSE));
printf("%-6s %5s %-63s\n",
timestr,
mktimestring(ep->length, TRUE),
mknotestring(ep));
}
found = lookup_next_entry(&lookup);
}
if (!numfound)
printf("no appointments on %s\n", mkdatestring(start));
return(numfound == 0);
}
/*
* signal handler. SIGHUP re-reads the database. It is sent when another
* plan program is started in non-interactive mode, by specifying an
* appointment on the command line. That entry should appear in our menus.
*/
static void sighand(sig)
int sig; /* signal type */
{
if (sig == SIGHUP) { /* re-read database */
signal(SIGHUP, sighand);
reread = TRUE;
} else { /* die */
(void)unlink(lockpath);
fprintf(stderr, "%s: killed with signal %d\n", progname, sig);
exit(0);
}
}
/*
* whenever something goes seriously wrong, this routine is called. It makes
* code easier to read. fatal() never returns. This may fail horribly if
* VARARGS is defined, but at least it's going to do *something*.
*/
#ifndef VARARGS
/*VARARGS*/
fatal(char *fmt, ...)
{
va_list parm;
va_start(parm, fmt);
fprintf(stderr, "%s: ", progname);
vfprintf(stderr, fmt, parm);
va_end(parm);
putc('\n', stderr);
exit(1);
}
#else
/*VARARGS*/
fatal(fmt, a, b, c, d)
char *fmt;
int a, b, c, d;
{
fprintf(stderr, fmt, a, b, c, d);
putc('\n', stderr);
exit(1);
}
#endif
/*
* Ultrix doesn't have strdup, so we'll need to define one locally.
*/
char *mystrdup(s)
register char *s;
{
register char *p = NULL;
if (s && (p = (char *)malloc(strlen(s)+1)))
strcpy(p, s);
return(p);
}
/*
* exit is redefined here so it the database is written back before the
* program dies for any reason - including Motif-Quit.
* How is this for a hack :-) That's what you get for downloading sources
* from alt.sources...
*/
void exit(ret)
{
static int exiting = 0;
if (!exiting++) {
if (*lockpath)
(void)unlink(lockpath);
if (mainlist && mainlist->modified) {
write_database(mainlist, DB_PUB_PATH, WR_PUBLIC |
WR_CONFIG);
write_database(mainlist, DB_PRIV_PATH, WR_PRIVATE);
resynchronize_daemon();
}
}
_exit(ret);
}
/*
* usage information
*/
static void usage()
{
fprintf(stderr, "Usage 1: %s [options]\nOptions:\n%s%s%s%s%s%s%s%s\n",
progname,
"\t-h\tprint this help text\n",
"\t-d\tdump fallback app-defaults and exit\n",
"\t-v\tprint version string\n",
"\t-t D\ttext dump for date D, default is today\n",
"\t\teg: -t, -t +3, -t tomorrow, -t 24.12., -t wed\n",
"\t-s\tstandalone, don't offer to start daemon\n",
"\t-f\tdon't fork on startup\n",
"\t-k\tignore lock file and start up in any case\n");
fprintf(stderr, "Usage 2: %s [mmdd]hhmm [message]*\n%s\n", progname,
"\tAdd appointment at mm/dd hh:mm (default is today)");
exit(1);
}
/*---------------------------------------------------------------------------*/
/*
* draw some text into a button. This is here because it's used by many
* routines. There are two versions, stdarg and varargs, because Sun has
* the gall to ship a pre-ansi compiler unless you pay extra...
*/
#ifndef VARARGS
print_button(Widget w, char *fmt, ...)
{
va_list parm;
Arg args;
XmString string;
char buf[1024];
if (fmt && w) {
va_start(parm, fmt);
vsprintf(buf, fmt, parm);
va_end(parm);
string = XmStringCreateSimple(*buf ? buf : " ");
XtSetArg(args, XmNlabelString, string);
XtSetValues(w, &args, 1);
XmStringFree(string);
}
}
print_text_button(Widget w, char *fmt, ...)
{
va_list parm;
char buf[1024];
if (w) {
va_start(parm, fmt);
vsprintf(buf, fmt, parm);
va_end(parm);
XmTextSetString(w, *buf ? buf : " ");
XmTextSetInsertionPosition(w, strlen(buf));
}
}
#else /* VARARGS */
print_button(w, fmt, a, b, c, d)
Widget w;
char *fmt;
int a, b, c, d;
{
Arg args;
XmString string;
char buf[1024];
if (fmt && w) {
sprintf(buf, fmt, a, b, c, d);
string = XmStringCreateSimple(buf);
XtSetArg(args, XmNlabelString, string);
XtSetValues(w, &args, 1);
XmStringFree(string);
}
}
print_text_button(w, fmt, a, b, c, d)
Widget w;
char *fmt;
int a, b, c, d;
{
XmString string;
char buf[1024];
if (w) {
sprintf(buf, fmt, a, b, c, d);
string = XmStringCreateSimple(buf);
XmTextSetString(w, *buf ? buf : " ");
XmTextSetInsertionPosition(w, strlen(buf));
XmStringFree(string);
}
}
#endif /* VARARGS */
/*
* draw a pixmap into a button, or remove the pixmap. The button must have
* been a pixmap button all along, this routine can't mix text and pixmaps.
* If <n> is -1, draw a blank pixmap.
*/
print_pixmap(w, n)
Widget w; /* button to draw into */
int n; /* pixmap #, one of PIC_* */
{
Arg args;
if (w) {
XtSetArg(args, XmNlabelPixmap, pixmap[n >= 0 ? n : PIC_BLANK]);
XtSetValues(w, &args, 1);
}
}
/*
* read resources and put them into the config struct. This routine is used
* for getting three types of resources: res_type={XtRInt,XtRBool,XtRString}.
*/
void get_rsrc(ret, res_name, res_class_name, res_type)
XtPointer ret;
char *res_name;
char *res_class_name;
char *res_type;
{
XtResource res_list[1];
res_list->resource_name = res_name;
res_list->resource_class = res_class_name;
res_list->resource_type = res_type;
res_list->resource_size = sizeof(res_type);
res_list->resource_offset = 0;
res_list->default_type = res_type;
res_list->default_addr = 0;
XtGetApplicationResources(toplevel, ret, res_list, 1, NULL, 0);
}
static void init_resources()
{
register struct config *c = &config;
get_rsrc(&c->calbox_xs[0], "calBoxWidth", "CalBoxWidth", XtRInt);
get_rsrc(&c->calbox_ys[0], "calBoxHeight", "CalBoxHeight", XtRInt);
get_rsrc(&c->calbox_marg[0], "calBoxMargin", "CalBoxMargin", XtRInt);
get_rsrc(&c->calbox_arrow[0],"calArrowWidth", "CalArrowWidth",XtRInt);
get_rsrc(&c->calbox_xs[1], "calBoxWidthSm", "CalBoxWidth", XtRInt);
get_rsrc(&c->calbox_ys[1], "calBoxHeightSm", "CalBoxHeight", XtRInt);
get_rsrc(&c->calbox_marg[1], "calBoxMarginSm", "CalBoxMargin", XtRInt);
get_rsrc(&c->calbox_arrow[1],"calArrowWidthSm","CalArrowWidth",XtRInt);
get_rsrc(&c->year_margin, "yearMargin", "YearMargin", XtRInt);
get_rsrc(&c->year_gap, "yearGap", "YearGap", XtRInt);
get_rsrc(&c->year_title, "yearTitle", "YearTitle", XtRInt);
get_rsrc(&c->yearbox_xs, "yearBoxWidth", "YearBoxWidth", XtRInt);
get_rsrc(&c->yearbox_ys, "yearBoxHeight", "YearBoxHeight",XtRInt);
get_rsrc(&c->week_margin, "weekMargin", "WeekMargin", XtRInt);
get_rsrc(&c->week_gap, "weekGap", "WeekGap", XtRInt);
get_rsrc(&c->week_daywidth, "weekDayWidth", "WeekDayWidth", XtRInt);
get_rsrc(&c->week_hourwidth, "weekHourWidth", "WeekHourWidth",XtRInt);
get_rsrc(&c->week_barheight, "weekBarHeight", "WeekBarHeight",XtRInt);
get_rsrc(&c->week_bargap, "weekBarGap", "WeekBarGap", XtRInt);
get_rsrc(&c->week_maxnote, "weekMaxNote", "WeekMaxNote", XtRInt);
get_rsrc(&c->showicontime, "showIconTime", "ShowIconTime",XtRBool);
get_rsrc(&c->frame_today, "frameToday", "FrameToday", XtRBool);
get_rsrc(&c->noicon, "noIcon", "NoIcon", XtRBool);
get_rsrc(&c->sgimode, "sgiMode", "SgiMode", XtRBool);
}
/*
* determine all colors, and allocate them. They can then be used by a call
* to set_color(COL_XXX).
*/
static void init_colors()
{
Screen *screen = DefaultScreenOfDisplay(display);
Colormap cmap;
XColor rgb;
int i, d;
char *c, *n, class_name[256];
cmap = DefaultColormap(display, DefaultScreen(display));
for (i=0; i < NCOLS; i++) {
switch (i) {
default:
case COL_STD: n = "colStd"; d=1; break;
case COL_BACK: n = "colBack"; d=0; break;
case COL_CALBACK: n = "colCalBack"; d=0; break;
case COL_CALSHADE: n = "colCalShade"; d=0; break;
case COL_CALACT: n = "colCalAct"; d=0; break;
case COL_CALTODAY: n = "colCalToday"; d=0; break;
case COL_CALFRAME: n = "colCalFrame"; d=0; break;
case COL_GRID: n = "colGrid"; d=1; break;
case COL_WEEKDAY: n = "colWeekday"; d=1; break;
case COL_WEEKEND: n = "colWeekend"; d=1; break;
case COL_NOTE: n = "colNote"; d=1; break;
case COL_NOTEOFF: n = "colNoteOff"; d=1; break;
case COL_TOGGLE: n = "colToggle"; d=1; break;
case COL_RED: n = "colRed"; d=1; break;
case COL_TEXTBACK: n = "colTextBack"; d=0; break;
case COL_YBACK: n = "colYearBack"; d=0; break;
case COL_YBOXBACK: n = "colYearBoxBack"; d=0; break;
case COL_YNUMBER: n = "colYearNumber"; d=1; break;
case COL_YWEEKDAY: n = "colYearWeekday"; d=1; break;
case COL_YMONTH: n = "colYearMonth"; d=1; break;
case COL_YTITLE: n = "colYearTitle"; d=1; break;
case COL_YGRID: n = "colYearGrid"; d=1; break;
case COL_HBLACK: n = "colHolidayBlack"; d=1; break;
case COL_HRED: n = "colHolidayRed"; d=1; break;
case COL_HGREEN: n = "colHolidayGreen"; d=1; break;
case COL_HYELLOW: n = "colHolidayYellow"; d=1; break;
case COL_HBLUE: n = "colHolidayBlue"; d=1; break;
case COL_HMAGENTA: n = "colHolidayMagenta";d=1; break;
case COL_HCYAN: n = "colHolidayCyan"; d=1; break;
case COL_HWHITE: n = "colHolidayWhite"; d=0; break;
case COL_WBACK: n = "colWeekBack"; d=0; break;
case COL_WBOXBACK: n = "colWeekBoxback"; d=0; break;
case COL_WTITLE: n = "colWeekTitle"; d=1; break;
case COL_WGRID: n = "colWeekGrid"; d=1; break;
case COL_WDAY: n = "colWeekDay"; d=1; break;
case COL_WNOTE: n = "colWeekNote"; d=1; break;
case COL_WFRAME: n = "colWeekFrame"; d=1; break;
case COL_WWARN: n = "colWeekWarn"; d=0; break;
case COL_WUSER_0: n = "colWeekUser_0"; d=0; break;
case COL_WUSER_1: n = "colWeekUser_1"; d=0; break;
case COL_WUSER_2: n = "colWeekUser_2"; d=0; break;
case COL_WUSER_3: n = "colWeekUser_3"; d=0; break;
case COL_WUSER_4: n = "colWeekUser_4"; d=0; break;
case COL_WUSER_5: n = "colWeekUser_5"; d=0; break;
case COL_WUSER_6: n = "colWeekUser_6"; d=0; break;
case COL_WUSER_7: n = "colWeekUser_7"; d=0; break;
}
strcpy(class_name, n);
class_name[0] &= ~('a'^'A');
get_rsrc(&c, n, class_name, XtRString);
if (!XParseColor(display, cmap, c, &rgb))
fprintf(stderr, "%s: unknown color \"%s\" (%s)\n",
progname, c, n);
else if (!XAllocColor(display, cmap, &rgb))
fprintf(stderr, "%s: can't alloc color \"%s\" (%s)\n",
progname, c, n);
else {
color[i] = rgb.pixel;
continue;
}
color[i] = d ? BlackPixelOfScreen(screen)
: WhitePixelOfScreen(screen);
}
}
set_color(col)
int col;
{
XSetForeground(display, jgc, color[col]);
XSetForeground(display, gc, color[col]);
}
/*
* load all fonts and make them available in the "fonts" struct. They are
* loaded into the GC as necessary.
*/
static void init_fonts()
{
int i;
char *f, class_name[256];
for (i=0; i < NFONTS; i++) {
switch (i) {
default:
#ifdef JAPAN
case FONT_STD: f = "stdFont"; break;
case FONT_JNOTE: f = "jNoteFont"; break;
#else
case FONT_STD: f = "fontList"; break;
#endif
case FONT_HELP: f = "helpFont"; break;
case FONT_DAY: f = "calNumberFont"; break;
case FONT_SMDAY: f = "calNumberFontSm"; break;
case FONT_NOTE: f = "calNoteFont"; break;
case FONT_YTITLE: f = "yearTitleFont"; break;
case FONT_YMONTH: f = "yearMonthFont"; break;
case FONT_YDAY: f = "yearWeekdayFont"; break;
case FONT_YNUM: f = "yearNumberFont"; break;
case FONT_WTITLE: f = "weekTitleFont"; break;
case FONT_WDAY: f = "weekDayFont"; break;
case FONT_WHOUR: f = "weekHourFont"; break;
case FONT_WNOTE: f = "weekNoteFont"; break;
}
strcpy(class_name, f);
class_name[0] &= ~('a'^'A');
get_rsrc(&f, f, class_name, XtRString);
if (!(font[i] = XLoadQueryFont(display, f))) {
fprintf(stderr, "plan: warning: bad font \"%s\"\n", f);
if (!(font[i] = XLoadQueryFont(display, "variable")) &&
!(font[i] = XLoadQueryFont(display, "fixed")))
fatal("can't load font \"variable\"\n", f);
}
}
config.calbox_title[0] = font[FONT_STD] ->max_bounds.ascent +
font[FONT_STD] ->max_bounds.descent;
config.calbox_title[1] = font[FONT_SMDAY] ->max_bounds.ascent +
font[FONT_SMDAY] ->max_bounds.descent;
config.week_title = font[FONT_WTITLE]->max_bounds.ascent +
font[FONT_WTITLE]->max_bounds.descent;
config.week_hour = font[FONT_WHOUR] ->max_bounds.ascent +
font[FONT_WHOUR] ->max_bounds.descent + 6;
}
/*
* get the process ID of the daemon. This pid gets a SIGHUP signal whenever
* the database has been written back to disk. The daemon then re-reads it.
* If there is no daemon, set the PID to 0.
*/
static PID_T daemon_pid; /* process ID of daemon (gets SIGHUP)*/
static void init_daemon()
{
int lockfd; /* lockfile descriptor */
char path[256]; /* lockfile path */
char buf[12]; /* contents of file (pid) */
daemon_pid = 0;
sprintf(path, LOCK_PATH, (int)getuid());
if ((lockfd = open(path, O_RDONLY)) < 0) {
if (!nodaemon) {
fprintf(stderr, "%s: WARNING: no daemon: ",progname);
perror("");
}
return;
}
if (read(lockfd, buf, 10) < 5) {
fprintf(stderr,"%s: WARNING: daemon lockfile %s unreadable: ",
progname, path);
perror("");
return;
}
close(lockfd);
buf[10] = 0;
daemon_pid = atoi(buf);
}
resynchronize_daemon()
{
if (!daemon_pid || kill(daemon_pid, SIGHUP)) {
init_daemon();
if (!nodaemon && (!daemon_pid || kill(daemon_pid, SIGHUP))) {
fprintf(stderr, "%s: WARNING: can't signal daemon: ",
progname);
perror("");
if (interactive)
create_nodaemon_popup();
else
fprintf(stderr,
"%s: WARNING: no daemon, run pland\n",
progname);
}
}
}
/*
* this routine gets called every 10 seconds. Redraw the main calendar when
* midnight passes, to move the green highlight. Write the main list if it
* has changed. Also, see if any old entries need to be recycled or deleted.
* If we got a SIGHUP signal, re-read the database when it is safe.
*/
/*ARGSUSED*/
static void timer_callback(data, id)
XtPointer data; /* not used */
XtIntervalId *id; /* not used */
{
static time_t last_tod; /* previous time-of-day */
time_t tod; /* current time-of-day */
timer_id = XtAppAddTimeOut(app, TIMER_PERIOD, timer_callback, 0);
tod = get_time();
set_tzone();
tod %= 86400;
if (tod < last_tod) {
draw_calendar();
draw_week_calendar();
}
if (tod/60 != last_tod/60) {
print_icon_name();
if (config.smallmonth)
print_button(mainmenu.time,
mktimestring(get_time(), FALSE));
else
print_button(mainmenu.time, "%s %s",
mkdatestring(get_time(), FALSE),
mktimestring(get_time(), FALSE));
}
last_tod = tod;
if (mainlist->modified && !mainlist->locked) {
write_database(mainlist, DB_PUB_PATH, WR_PUBLIC | WR_CONFIG);
write_database(mainlist, DB_PRIV_PATH, WR_PRIVATE);
resynchronize_daemon();
}
if (!mainlist->modified && !mainlist->locked && reread) {
reread = FALSE;
destroy_list(&mainlist);
(void)readfile(&mainlist, DB_PUB_PATH, TRUE);
(void)readfile(&mainlist, DB_PRIV_PATH, FALSE);
draw_calendar();
update_all_listmenus();
}
if (config.autodel && recycle_all(mainlist, TRUE, 0)) {
draw_calendar();
update_all_listmenus();
}
}